package com.pk.platform.business.core.dao.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.pk.platform.business.core.dao.IGenericDao;
import com.pk.platform.util.StringConverter;
import com.pk.platform.util.page.ListPage;
import com.pk.platform.util.page.Pager;

public class GenericDaoImpl extends HibernateDaoSupport implements IGenericDao {

	private SimpleJdbcTemplate sjt;
	
	private JdbcTemplate jt;
	
    public <T> void add(T entity)
    {
    	this.getHibernateTemplate().save(entity);
    }

    public <T> void update(T entity) {
    	this.getSession().merge(entity);
    }
  
    public <T> void delete(Class<T> entityClass, Serializable... entityids)
    {
         for (Serializable id : entityids) {
             getHibernateTemplate().delete(getHibernateTemplate().load(entityClass, id));
         }
    }

    public <T> T get(Class<T> entityClass, Serializable id) {
        return (T) getHibernateTemplate().get(entityClass, id);
    }
    
    public boolean exist(String tableName, String fieldName, String value)
    {
    	StringBuffer sql = new StringBuffer();
    	sql.append("select count(*) from ").append(tableName).append(" where ").append(fieldName).append(" = ?");
    	Integer count = this.getSjt().queryForInt(sql.toString(), value);
    	if(count.intValue() > 0)
    		return true;
    	else return false;
    }

    public ListPage getListPage(String sql, Object[] parameterValues, Pager pager)
    {
    	if(pager == null)
    		pager = new Pager();
    	if(pager.getThisPage() == 0)
    		pager.setThisPage(1);
    	ListPage listPage = new ListPage();
    	int total = this.getTotal(sql, parameterValues);
    	int pageCount = (total % pager.getPageSize() == 0) ? (total / pager.getPageSize()) : (total / pager.getPageSize() + 1);
    	pager.setTotal(total);
    	pager.setPageCount(pageCount);
    	
    	int index = sql.lastIndexOf(" order by");
    	String s = sql;
    	
		if(pager.getSortField() != null && !"".equals(pager.getSortField()))
		{
			if(index > 0)
	    	{
    			s = s.substring(0, index) + " order by " + pager.getSortField() + pager.getSortType(); //��order by���Ժ���ֶλ�Ϊ����������ֶ�
    		}
			else
			{
				s += " order by " + pager.getSortField() + pager.getSortType(); //ֱ����������ֶ�
			}
		}
    	
    	try
    	{
    		String[] names = this.getColumnName(s, parameterValues);
	    	Query q = this.getSession().createSQLQuery(s);
	    	int first = (pager.getThisPage() - 1) * pager.getPageSize();
	    	q.setFirstResult(first);
	    	q.setMaxResults(pager.getPageSize());
	    	this.setParameterValues(q, parameterValues);
	    	List<Object> list = q.list();
	    	List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
	    	int size = list.size();
	    	for(int i = 0; i < size; i++)
	    	{
	    		Object[] obj = (Object[])list.get(i);
	    		int length = obj.length;
	    		Map<String, Object> map = new LinkedHashMap<String, Object>();
	    		for(int j = 0; j < length; j++)
	    		{
	    			map.put(names[j], obj[j]);
	    		}
	    		mapList.add(map);
	    	}
	    	
	    	listPage.setPager(pager);
	    	listPage.setList(mapList);
    	}
    	catch (Exception e)
    	{
			e.printStackTrace();
		}
    	return listPage;    	
    }
    
    public List<Map<String, Object>> getListByPage(String sql, Object[] parameterValues, Pager pager)
    {
    	if(pager == null)
    		pager = new Pager();
    	if(pager.getThisPage() == 0)
    		pager.setThisPage(1);
    	List<Map<String, Object>> listPage = new ArrayList<Map<String,Object>>();
    	int total = this.getTotal(sql, parameterValues);
    	if(pager.getPageSize() == 0)
    	{
    		pager.setPageSize(15);
    	}
    	int pageCount = (total % pager.getPageSize() == 0) ? (total / pager.getPageSize()) : (total / pager.getPageSize() + 1);
    	pager.setTotal(total);
    	pager.setPageCount(pageCount);
    	
    	try
    	{
    		String[] names = this.getColumnName(sql, parameterValues);
    		StringBuffer s = new StringBuffer();
    		s.append("select * from (").append(sql).append(") t999");
    		if(StringConverter.isNotNull(pager.getSortField()))
    		{
    			s.append(" order by ").append(pager.getSortField()).append(" ").append(pager.getSortType());
    		}
	    	Query q = this.getSession().createSQLQuery(s.toString());
	    	int first = (pager.getThisPage() - 1) * pager.getPageSize();
	    	q.setFirstResult(first);
	    	q.setMaxResults(pager.getPageSize());
	    	this.setParameterValues(q, parameterValues);
	    	List<Object> list = q.list();
	    	int size = list.size();
	    	for(int i = 0; i < size; i++)
	    	{
	    		Object[] obj = (Object[])list.get(i);
	    		int length = obj.length;
	    		Map<String, Object> map = new LinkedHashMap<String, Object>();
	    		for(int j = 0; j < length; j++)
	    		{
	    			map.put(names[j], obj[j]);
	    		}
	    		listPage.add(map);
	    	}
    	}
    	catch (Exception e)
    	{
			e.printStackTrace();
		}
    	return listPage;    	
    }
    
    
    /**
     * <description> �����������
     * @param sql
     * @param parameterValues
     * @return
     */
    public int getTotal(String sql, Object[] parameterValues)
    {
    	String s = sql;
    	int index = s.lastIndexOf("order by");
    	if(index > 0)
    		s = s.substring(0, index);
    	String countSql = "select count(*) as total from ( " + s + " ) as table_one";
    	int count = this.getSjt().queryForInt(countSql, parameterValues);
    	return count;
    }
    
    /**
     * ���ò����ֵ
     * @param query
     * @param parameterValues
     */
    private void setParameterValues(Query query, Object[] parameterValues) {
        if (parameterValues != null && parameterValues.length > 0) {            
            for (int i=0;i<parameterValues.length;i++) {         
                    query.setParameter(i, parameterValues[i]);
            }
        }
    }
    
    private String[] getColumnName(String sql, Object[] parameterValues)
    {
    	String[] names = null;
    	Connection conn = null;
    	PreparedStatement ps = null;
    	ResultSet rs = null;
    	Session session = null;
    	try
    	{
    	    session = this.getSession();
    		conn = session.connection();
    		ps = conn.prepareStatement(sql);
    		this.setSqlParameterValues(ps, parameterValues);
    		rs = ps.executeQuery();
    		ResultSetMetaData rsmd = rs.getMetaData();
    		int count = rsmd.getColumnCount();
    		names = new String[count];
    		for(int i = 0; i < count; i++)
    		{
    			names[i] = rsmd.getColumnName(i + 1);
    		}
    	}
    	catch (Exception e)
    	{
			e.printStackTrace();
		}
    	finally
    	{
    		try
    		{
    			rs.close();
        		ps.close();
    		}
    		catch (Exception e)
    		{
				
			}
    	}
    	return names;
    }

    public Session getHibernateSession()
    {
    	return this.getSession();
    }
    
    private void setSqlParameterValues(PreparedStatement ps, Object[] parameterValues) {
        if (parameterValues != null && parameterValues.length > 0) {
        	try
        	{
	            for (int i = 0;i < parameterValues.length; i++) {
	                ps.setObject(i + 1, parameterValues[i]);
	            }
        	}
        	catch (Exception e)
        	{
				e.printStackTrace();
			}
        }
    }

    
    public void setDataSource(DataSource ds)
    {
    	jt = new JdbcTemplate(ds);
    	sjt = new SimpleJdbcTemplate(jt);
    }

	public SimpleJdbcTemplate getSjt() {
		return sjt;
	}

	public void setSjt(SimpleJdbcTemplate sjt) {
		this.sjt = sjt;
	}

	public JdbcTemplate getJt() {
		return jt;
	}

	public void setJt(JdbcTemplate jt) {
		this.jt = jt;
	}

}
